﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace M3G {
    public class Fog : Object3D {
        #region Constant
        public const int Exponential        = 80;
        public const int Linear             = 81;
        public const int ExponentialSquared = 82;
        #endregion

        #region Field
        int   mode;
        float density;
        float nearDistance;
        float farDistance;
        uint  color;
        #endregion

        #region Method
        public Fog () {
            this.mode = Fog.Linear;
            this.density = 1.0f;
            this.nearDistance = 0.0f;
            this.farDistance = 1.0f;
            this.color = 0x00000000u;
        }

        protected Fog (Fog fog)
            : base (fog) {
            this.mode = fog.mode;
            this.density = fog.density;
            this.nearDistance = fog.nearDistance;
            this.farDistance = fog.farDistance;
            this.color = fog.color;
        }

        public int Mode {
            get { return mode; }
            set {
                var mode = value;
                if (mode < Fog.Exponential || mode > Fog.ExponentialSquared) {
                    throw new ArgumentException ("Fog mode must be Linear,Exponential,ExponentialSquared, mode=" + mode);
                }

                this.mode = mode;
            }
        }

        public uint Color {
            get { 
                return color;
            }
            set {
                this.color = value & 0x00ffffff; 
            }
        }

        public float Density {
            get { 
                return density;
            }
            set {
                var density = value;
                if (density < 0) {
                    throw new ArgumentException ("Density must be positive number or 0, d=" + density);
                }

                this.density = density;
            }
        }

  


        public float NearDistance {
            get { return nearDistance; }
        }

        public float FarDistance {
            get { return farDistance; }
        }

        public void SetLinear (float near, float far) {
            this.nearDistance = near;
            this.farDistance = far;
        }

        public override int Animate (int time) {

            base.Animate (time);

            var animatedColor        = new float[3];
            var animatedDensity      = new float[1];
            var animatedNearDistance = new float[1];
            var animatedFarDistance  = new float[1];
            var value                = new float[3];
            var animated             = new Dictionary<int, bool> (4);

            for (var i=0; i < AnimationTrackCount; i++) {
                var track = AnimationTrack[i];
                var ch    = AnimationTrackChannel[i];
                if (track.Controller == null || !track.Controller.Active (time)) {
                    continue;
                }
                var property = track.TargetProperty;
                var weight   = track.Controller.Weight;

                animated[property] = true;
                switch (property) {
                    case M3G.AnimationTrack.Color: {
                        track.Sample (time, ch, value);
                        animatedColor[0] = value[0] * weight;
                        animatedColor[1] = value[1] * weight;
                        animatedColor[2] = value[2] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.Density: {
                        track.Sample (time, ch, value);
                        animatedDensity[0] = value[0] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.NearDistance: {
                        track.Sample (time, ch, value);
                        animatedNearDistance[0] = value[0] * weight;
                        break;
                    }
                    case M3G.AnimationTrack.FarDistance: {
                        track.Sample (time, ch, value);
                        animatedFarDistance[0] = value[0] * weight;
                        break;
                    }
                }// switch
            }  // for

            if (animated[M3G.AnimationTrack.Color]) {
                var r = (uint)animatedColor[0].Clamp (0, 1) * 255;
                var g = (uint)animatedColor[1].Clamp (0, 1) * 255;
                var b = (uint)animatedColor[2].Clamp (0, 1) * 255;
                this.color = (r << 16) | (g << 8) | (b << 0);
            }
            if (animated[M3G.AnimationTrack.Density]) {
                this.density = animatedDensity[0];
            }
            if (animated[M3G.AnimationTrack.NearDistance]) {
                this.nearDistance = animatedNearDistance[0];
            }
            if (animated[M3G.AnimationTrack.FarDistance]) {
                this.farDistance = animatedFarDistance[0];
            }

            return 0;
        }

        public override Object3D Duplicate () {
            return new Fog (this);
        }

        #endregion
    }
}
